package com.ywu.application.standard.menu.service;

import com.google.gson.internal.LinkedTreeMap;
import com.ywu.application.standard.component.api.ComponentApi;
import com.ywu.application.standard.component.dto.ComponentDto;
import com.ywu.application.standard.component.entity.ComponentEntity;
import com.ywu.application.standard.role.api.MenuRoleAuthApi;
import com.ywu.application.standard.role.dto.MenuRoleAuthDto;
import com.ywu.boot.context.YwuContext;
import com.ywu.boot.context.YwuContextHolder;
import com.ywu.boot.context.YwuContextRole;
import com.ywu.boot.exception.YwuRuntimeException;
import com.ywu.boot.utils.RedisUtils;
import com.ywu.common.constant.CommonConstant;
import com.ywu.common.entity.PageInfo;
import com.ywu.common.entity.PageList;
import com.ywu.common.gson.GsonUtils;
import com.ywu.common.result.CommonResult;
import com.ywu.application.standard.menu.constant.MenuConstant;
import com.ywu.application.standard.menu.data.MenuRepository;
import com.ywu.application.standard.menu.data.RouterPathRepository;
import com.ywu.application.standard.menu.dto.MenuDto;
import com.ywu.application.standard.menu.dto.MenuPermissionDto;
import com.ywu.application.standard.menu.dto.RouterPathDto;
import com.ywu.application.standard.menu.dto.search.MenuSearchDto;
import com.ywu.application.standard.menu.entity.MenuEntity;
import com.ywu.application.standard.menu.entity.MenuPermissionEntity;
import com.ywu.application.standard.menu.entity.RouterPathEntity;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName MenuService
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/2/24 19:20
 * @Version 1.0
 **/
@Service
public class MenuService {
    private final static Logger log = LoggerFactory.getLogger(MenuService.class);

    @Autowired
    private MenuRepository menuRepository;

    @Autowired
    private RouterPathRepository routerPathRepository;

    @Autowired
    private MenuCheckService menuCheckService;

    @Autowired
    private RouterPathService routerPathService;

    @Autowired
    private ComponentApi componentApi;

    @Autowired
    private MenuRoleAuthApi menuRoleAuthApi;

    private static final String YWU_MENU_PERMISSION_REDIS_KEY = "YWU_MENU_PERMISSION:menu";

    private static final String YWU_MENU_REGISTER_QUERY_KEY = "YWU_MENU_REGISTER_QUERY:menu";

    private static final String YWU_MENU_ROUTE_INFO_KEY = "YWU_MENU_ROUTE_INFO:menu";

    /**
    * @Author GroundDemo
    * @Description 查询所有菜单信息
    * @Date 19:21 2024/2/24
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> getAllMenuInfo(MenuDto menuDto) {
        // 存儲要返回的数据
        List<MenuDto> resMenuDtos = new ArrayList<>();
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        menuDto.setTenantId(currentContext.getYwuContextTenant().getTenantId());
        // 查询所有菜单后续进行代码匹配
        List<MenuEntity> menuEntities = menuRepository.queryAllMenu(menuDto);
        HashSet<Integer> repeatSet = new HashSet<>();
        List<MenuEntity> handleEntity = new ArrayList<>();
        // 父菜单关联子菜单
        Map<Integer, List<MenuEntity>> parentToSon = new HashMap<>();
        for (MenuEntity tempEntity : menuEntities) {
            if (tempEntity.getParentId() != 0) {
                if (parentToSon.containsKey(tempEntity.getParentId())) {
                    List<MenuEntity> tempList = parentToSon.get(tempEntity.getParentId());
                    tempList.add(tempEntity);
                } else {
                    List<MenuEntity> tempList = new ArrayList<>();
                    tempList.add(tempEntity);
                    parentToSon.put(tempEntity.getParentId(), tempList);
                }
            }
        }
        Map<Integer, MenuEntity> menuMap = menuEntities.stream().collect(Collectors.toMap(MenuEntity::getId, MenuEntity -> MenuEntity, (value1, value2) -> value1));
        // 按条件过滤出结果
        List<MenuEntity> matchMenuEntities = menuEntities.stream().filter(res -> StringUtils.isBlank(menuDto.getName()) || StringUtils.equals(menuDto.getName(), res.getName()))
                .filter(res -> StringUtils.isBlank(menuDto.getCnName()) || StringUtils.equals(menuDto.getCnName(), res.getCnName()))
                .filter(res -> StringUtils.isBlank(menuDto.getStatus()) || StringUtils.equals(menuDto.getStatus(), res.getStatus()))
                .collect(Collectors.toList());
        // 根据查询接口向下卷积子数据
        for (MenuEntity tempEntity : matchMenuEntities) {
            handleParentMenuInfo(parentToSon, tempEntity, repeatSet, handleEntity);
        }
        // 卷积父子数据
        for (MenuEntity entity : matchMenuEntities) {
            handleSearchMenuInfo(entity, repeatSet, handleEntity, menuMap);
        }
        // 所有对象的转换
        ArrayList<MenuDto> menuDtos = new ArrayList<>();
        tranceEntity(menuDtos, handleEntity);
        // 关联组件、路由文根
        relateComponentRouteRoot(menuDtos);
        // 处理children数据
        handleMenuChildrenInfo(menuDtos, resMenuDtos);
        return CommonResult.success(resMenuDtos);
    }

    /**
    * @Author GroundDemo
    * @Description 关联组件和路由文根
    * @Date 10:57 2024/3/31
    * @Param [menuDtos]
    * @return void
    **/
    private void relateComponentRouteRoot(ArrayList<MenuDto> menuDtos) {
        // 查询路由组件列表
        ComponentDto componentDto = new ComponentDto();
        PageInfo pageInfo = new PageInfo();
        pageInfo.setPageIndex(1);
        pageInfo.setPageSize(10000);
        componentDto.setPageInfo(pageInfo);
        componentDto.setComponentType("CUSTOM");
        CommonResult<Object> componentRes = componentApi.queryComponentsWithNoContent(componentDto);
        Object componentData = componentRes.getData();
        PageList<LinkedTreeMap<String, Object>> componentDeserialize = GsonUtils.deserialize(GsonUtils.serialize(componentData), PageList.class);
        List<LinkedTreeMap<String, Object>> componentDataList = componentDeserialize.getDataList();
        log.debug("relateComponentRouteRoot componentDataList {}", GsonUtils.serialize(componentDataList));
        // 查询路由文根列表
        RouterPathDto routerPathDto = new RouterPathDto();
        routerPathDto.setPageInfo(pageInfo);
        CommonResult<Object> routeRootPathRes = routerPathService.queryRouteRootPath(routerPathDto);
        Object routeRootPathData = routeRootPathRes.getData();
        PageList<LinkedTreeMap<String, Object>> routeRootPathDeserialize = GsonUtils.deserialize(GsonUtils.serialize(routeRootPathData), PageList.class);
        List<LinkedTreeMap<String, Object>> routeRootPathDataList = routeRootPathDeserialize.getDataList();
        log.debug("relateComponentRouteRoot routeRootPathDataList {}", GsonUtils.serialize(routeRootPathDataList));
        // 关联组件-路由文根
        for (MenuDto dto : menuDtos) {
            // 关联组件
            if (StringUtils.equals(dto.getMenuType(), "DYNAMIC")) {
                Integer componentId = dto.getComponentId();
                Double aDouble = new Double(componentId);
                List<LinkedTreeMap<String, Object>> collect = componentDataList.stream().filter(res -> ((Double)res.get("id")).equals(aDouble)).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(collect)) {
                    dto.setComponentName((String) collect.get(0).get("componentCnName"));
                }
            }
            // 关联路由文根
            Integer routeRootId = dto.getRouteRootId();
            Double aDouble = new Double(routeRootId);
            List<LinkedTreeMap<String, Object>> collect = routeRootPathDataList.stream().filter(res -> ((Double)res.get("id")).equals(aDouble)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(collect)) {
                dto.setRouteRootName((String) collect.get(0).get("routeRootName"));
            }
        }
    }

    private void handleParentMenuInfo(Map<Integer, List<MenuEntity>> parentToSon, MenuEntity tempEntity,
                                      HashSet<Integer> repeatSet, List<MenuEntity> handleEntity) {
        if (parentToSon.containsKey(tempEntity.getId())) {
            // 向下卷积子数据
            List<MenuEntity> sonEntities = parentToSon.get(tempEntity.getId());
            for (MenuEntity sonEntity : sonEntities) {
                if (!repeatSet.contains(sonEntity.getId())) {
                    // 查询的是父菜单，直接添加
                    repeatSet.add(sonEntity.getId());
                    handleEntity.add(sonEntity);
                    if (parentToSon.containsKey(sonEntity.getId())) {
                        handleParentMenuInfo(parentToSon, sonEntity, repeatSet, handleEntity);
                    }
                }
            }
        }
    }

    private void handleSearchMenuInfo(MenuEntity entity, HashSet<Integer> repeatSet,
                                      List<MenuEntity> handleEntity, Map<Integer, MenuEntity> menuMap) {
        if (entity.getParentId() == 0) {
            if (!repeatSet.contains(entity.getId())) {
                // 查询的是父菜单，直接添加
                repeatSet.add(entity.getId());
                handleEntity.add(entity);
            }
        } else {
            // 查询的是子菜单，调用递归的方式添加数据
            if (!repeatSet.contains(entity.getId())) {
                repeatSet.add(entity.getId());
                handleEntity.add(entity);
                if (menuMap.containsKey(entity.getParentId())) {
                    MenuEntity parentEntity = menuMap.get(entity.getParentId());
                    handleSearchMenuInfo(parentEntity, repeatSet, handleEntity, menuMap);
                }
            }
        }
    }

    /**
    * @Author GroundDemo
    * @Description 查询菜单的动态路由
    * @Date 11:39 2024/2/25
    * @Param []
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> getMenuRouterInfo() {
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        String tenantId = currentContext.getYwuContextTenant().getTenantId();
        Integer id = currentContext.getYwuContextUser().getId();
        // 优先从缓存中获取数据
        String redisInfo = RedisUtils.getHashByKey(YWU_MENU_ROUTE_INFO_KEY, tenantId + '-' + id);
        if (Objects.nonNull(redisInfo)) {
            log.debug("menu route info using redis cache");
            List<MenuDto> menuDtos = GsonUtils.deserializeList(redisInfo, MenuDto.class);
            return CommonResult.success(menuDtos);
        }
        // 存儲要返回的数据
        List<MenuDto> resMenuDtos = new ArrayList<>();

        // 除了查询本租户下的所有菜单之外，还需查询授权本用户的所有菜单
        List<YwuContextRole> ywuContestRole = currentContext.getYwuContestRole();
        List<String> roleCodes = ywuContestRole.stream().map(YwuContextRole::getRoleCode).collect(Collectors.toList());
        List<MenuEntity> resEntity = menuRepository.queryTenantAndPermissionList(tenantId, roleCodes);
        // 所有对象的转换
        ArrayList<MenuDto> menuDtos = new ArrayList<>();
        tranceEntity(menuDtos, resEntity);
        // 关联组件、路由文根
        relateComponentRouteRoot(menuDtos);
        handleMenuChildrenInfo(menuDtos, resMenuDtos);
        // 将解析结果进行缓存
        addMenuRouterInfoRedisCache(resMenuDtos);
        return CommonResult.success(resMenuDtos);
    }

    /**
    * @Author GroundDemo
    * @Description 解析父子层级菜单
    * @Date 12:39 2025/3/22
    * @Param [menuDtos, resMenuDtos]
    * @return void
    **/
    private void handleMenuChildrenInfo(ArrayList<MenuDto> menuDtos, List<MenuDto> resMenuDtos) {
        // 根据ID为键转换为map集合
        Map<Integer, MenuDto> menuDtoMap = menuDtos.stream().collect(Collectors.toMap(MenuDto::getId, MenuDto -> MenuDto, (value1, vaule2) -> value1));
        HashMap<Integer, List<MenuDto>> resHashMap = new HashMap<>();
        // 父模板和子模板归类
        for (MenuDto dto : menuDtos) {
            if (resHashMap.containsKey(dto.getParentId())) {
                List<MenuDto> dtoList = resHashMap.get(dto.getParentId());
                dtoList.add(dto);
            } else {
                List<MenuDto> dtoList = new ArrayList<>();
                dtoList.add(dto);
                resHashMap.put(dto.getParentId(), dtoList);
            }
        }
        List<Integer> sortedKeys = resHashMap.keySet().stream().sorted().collect(Collectors.toList());
        for (Integer key : sortedKeys) {
            // 插入所有子菜单
            List<MenuDto> children = resHashMap.get(key);
            if (key == 0) {
                resMenuDtos.addAll(children);
                continue;
            }
            if (menuDtoMap.containsKey(key)) {
                MenuDto parent = menuDtoMap.get(key);
                parent.setChildren(children);
            }
        }
    }
    
    /**
    * @Author GroundDemo
    * @Description 转换entity对象
    * @Date 17:57 2024/2/25
    * @Param []
    * @return void
    **/
    private void tranceEntity(ArrayList<MenuDto> menuDtos, List<MenuEntity> resEntity) {
        for (MenuEntity entity : resEntity) {
            MenuDto menuDto = new MenuDto();
            BeanUtils.copyProperties(entity, menuDto);
            menuDtos.add(menuDto);
        }
    }

    /**
    * @Author GroundDemo
    * @Description 查询所有菜单合并子菜单的形式
    * @Date 20:35 2024/2/25
    * @Param []
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> getAllMenuNoChildrenInfo() {
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        MenuDto menuDto = new MenuDto();
        menuDto.setTenantId(currentContext.getYwuContextTenant().getTenantId());
        List<MenuEntity> menuEntities = menuRepository.queryAllMenu(menuDto);
        return CommonResult.success(menuEntities);
    }

    /**
    * @Author GroundDemo
    * @Description 添加菜单
    * @Date 18:45 2024/2/26
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> addMenuInfo(MenuDto menuDto) {
        CommonResult<Object> checkRes = menuCheckService.checkMetaInfo(menuDto);
        if (Objects.nonNull(checkRes)) {
            return checkRes;
        }
        // 设置routeTo
        resetRouteTo(menuDto);
        // 校验routeTo是否存在
        if (checkRouteTo(menuDto.getRouteTo())) {
            return CommonResult.error().setErrorCode("route to is exist")
                    .setMessage("路由已经被其他菜单使用");
        }
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        menuDto.createInfo(currentContext.getYwuContextUser().getUserAccount());
        menuDto.setTenantId(currentContext.getYwuContextTenant().getTenantId());
        if (Objects.isNull(menuDto.getOrderNum())) {
            menuDto.setOrderNum(0);
        }
        // 添加菜单
        menuRepository.addMenu(menuDto);
        // 删除缓存
        deleteMenuRouterInfoRedisCache();
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 校验routeTo是否存在
    * @Date 20:07 2024/6/2
    * @Param [routeTo]
    * @return boolean
    **/
    private boolean checkRouteTo(String routeTo) {
        MenuSearchDto searchDto = new MenuSearchDto();
        searchDto.setRouteTo(routeTo);
        MenuEntity menuEntity = menuRepository.queryOne(searchDto);
        return Objects.nonNull(menuEntity) && Objects.nonNull(menuEntity.getId());
    }

    /**
    * @Author GroundDemo
    * @Description 修改菜单
    * @Date 21:15 2024/2/26
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> updateMenuInfo(MenuDto menuDto) {
        CommonResult<Object> checkRes = menuCheckService.checkMetaInfo(menuDto);
        if (Objects.nonNull(checkRes)) {
            return checkRes;
        }
        // 判断菜单是否存在
        MenuSearchDto dto = new MenuSearchDto();
        dto.setId(menuDto.getId());
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        dto.setTenantId(currentContext.getYwuContextTenant().getTenantId());
        MenuEntity menuEntity = menuRepository.checkMenuEntity(dto);
        if (Objects.isNull(menuEntity) || Objects.isNull(menuEntity.getId())) {
            return CommonResult.error().setMessage("menu not exist").setCode(CommonConstant.ERROR_CODE);
        }
        // 设置routeTo
        resetRouteTo(menuDto);
        // 校验routeTo是否存在
        if (!StringUtils.equals(menuEntity.getRouteTo(), menuDto.getRouteTo()) && checkRouteTo(menuDto.getRouteTo())) {
            return CommonResult.error().setErrorCode("route to is exist")
                    .setMessage("路由已经被其他菜单使用");
        }
        // 修改菜单
        menuRepository.updateMenu(menuDto);
        // 删除缓存
        deleteMenuRegisterQueryRedisCache(menuDto.getRouteTo());
        deleteMenuRouterInfoRedisCache();
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 设置routeTo
    * @Date 21:16 2024/2/26
    * @Param [menuDto]
    * @return void
    **/
    private void resetRouteTo(MenuDto menuDto) {
        MenuSearchDto menuSearchDto = new MenuSearchDto();
        menuSearchDto.setId(menuDto.getParentId());
        String routeTo = "";
        // 查询挂载文根
        RouterPathDto routerPathDto = new RouterPathDto();
        routerPathDto.setId(menuDto.getRouteRootId());
        CommonResult<Object> routeRootPathRes = routerPathService.queryRouteRootPath(routerPathDto);
        if (!StringUtils.equals(routeRootPathRes.getCode(), "200")) {
            throw new YwuRuntimeException("路由文根查询失败");
        }
        PageList<RouterPathEntity> data = (PageList<RouterPathEntity>) routeRootPathRes.getData();
        List<RouterPathEntity> dataList = data.getDataList();
        if (CollectionUtils.isEmpty(dataList)) {
            throw new YwuRuntimeException("路由文根查询失败");
        }
        RouterPathEntity routeRootPathInfo = dataList.get(0);
        log.debug("test ywu {}", GsonUtils.serialize(routeRootPathInfo));
        String routeRootPath = routeRootPathInfo.getRouteRootPath();
        // 将后缀拦截
        if (routeRootPath.endsWith("/")) {
            routeRootPath = routeRootPath.substring(0, routeRootPath.length() - 1);
        }
        // 查询父菜单
        MenuEntity parentEntity = menuRepository.queryOne(menuSearchDto);
        String routePath = menuDto.getRoutePath();
        if (!routePath.startsWith("/")) {
            routePath = "/" + menuDto.getRoutePath();
        }
        // 根据父菜单填充routeTo
        if (Objects.nonNull(parentEntity)) {
            if (parentEntity.getRouteTo().endsWith("/")) {
                routeTo = parentEntity.getRouteTo().substring(0, parentEntity.getRouteTo().length() - 1) + routePath;
            } else {
                routeTo = parentEntity.getRouteTo() + routePath;
            }
        } else {
            routeTo = routeRootPath + routePath;
        }
        menuDto.setRouteTo(routeTo);
    }

    /**
    * @Author GroundDemo
    * @Description 删除菜单
    * @Date 22:09 2024/2/26
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> deleteMenuInfo(MenuDto menuDto) {
        if (Objects.isNull(menuDto.getId())) {
            return CommonResult.error().setErrorCode(MenuConstant.ID_IS_NOT_EXIST_ERROR.getErrorCode())
                    .setCode(MenuConstant.ID_IS_NOT_EXIST_ERROR.getCode())
                    .setMessage(MenuConstant.ID_IS_NOT_EXIST_ERROR.getMessage());
        }
        // 判断菜单是否存在
        MenuSearchDto searchDto = new MenuSearchDto();
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        searchDto.setTenantId(currentContext.getYwuContextTenant().getTenantId());
        searchDto.setId(menuDto.getId());
        MenuEntity menuEntity = menuRepository.checkMenuEntity(searchDto);
        if (Objects.isNull(menuEntity) || Objects.isNull(menuEntity.getId())) {
            return CommonResult.error().setMessage("menu not exist").setCode(CommonConstant.ERROR_CODE);
        }
        menuRepository.deleteById(menuDto.getId());
        // 删除菜单的授权
        MenuRoleAuthDto menuRoleAuthDto = new MenuRoleAuthDto();
        menuRoleAuthDto.setMenuId(menuEntity.getId());
        menuRoleAuthApi.menuRoleAuthDeleteInfo(menuRoleAuthDto);
        // 删除缓存
        deleteMenuRegisterQueryRedisCache(menuEntity.getRouteTo());
        deleteMenuRouterInfoRedisCache();
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 菜单组件查询 - 配合前端实现菜单组件的动态注册
    * @Date 19:56 2024/8/17
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> menuComponentRegisterQuery(MenuDto menuDto) {
        String requestRouteTo = menuDto.getRouteTo().split("\\?")[0];
        // 优先查询缓存数据
        String redisInfo = RedisUtils.getHashByKey(YWU_MENU_REGISTER_QUERY_KEY, requestRouteTo);
        if (Objects.nonNull(redisInfo)) {
            log.debug("menu component register query using redis cache");
            Map deserialize = GsonUtils.deserialize(redisInfo, Map.class);
            return CommonResult.success(deserialize);
        }
        // 查询所有的菜单
        List<MenuEntity> menuEntityList = menuRepository.queryAllMenuInfo();
        // 根据routeTo查询菜单路径
        List<MenuEntity> filterRes = menuEntityList.stream().filter(res -> StringUtils.equals(res.getRouteTo(), requestRouteTo)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(filterRes)) {
            return CommonResult.error().setErrorCode("menu.path.is.not.exist");
        }
        MenuEntity entity = filterRes.get(0);
        // 构建一整个返回对象
        Map<String, Object> resMap = new HashMap<>();
        // 如果当前查询出结果的租户ID根当前的租户不一致, 查询菜单相关的授权
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        if (!currentContext.getYwuContextTenant().getTenantId().equals(entity.getTenantId())) {
            List<MenuPermissionEntity> permissionList = getMenuPermissionRole(String.valueOf(entity.getId()));
            Set<String> roleCodePermission = permissionList.stream().map(MenuPermissionEntity::getRoleCode).collect(Collectors.toSet());
            List<YwuContextRole> ywuContestRole = currentContext.getYwuContestRole();
            Set<String> userRoleCodes = ywuContestRole.stream().map(YwuContextRole::getRoleCode).collect(Collectors.toSet());
            // 校验当前用户的角色与菜单授权的角色是否存在交集
            if (Collections.disjoint(roleCodePermission, userRoleCodes)) {
                // 不存在交集，无权限，返回异常
                return CommonResult.error().setErrorCode("menu.path.is.not.exist");
            }
        }
        // 向上卷积父菜单的数据 卷积的同时记录一些组件变量后续使用
        Set<Integer> routeRootIds = new HashSet<>();
        Set<Integer> componentIds = new HashSet<>();
        Map<Integer, MenuEntity> collect = menuEntityList.stream().collect(Collectors.toMap(MenuEntity::getId, Function.identity()));
        MenuDto dto = new MenuDto();
        BeanUtils.copyProperties(entity, dto);
        MenuDto parentInfo = getMenuParentInfo(collect, dto, routeRootIds, componentIds);
        // 查询路由文根相关信息
        List<RouterPathEntity> routerPathEntityList = routerPathRepository.queryRoutePathInfoByIds(new ArrayList<>(routeRootIds));
        routerPathEntityList.forEach(res -> componentIds.add(res.getComponentId()));
        log.debug("routerPathEntityList {}", GsonUtils.serialize(routerPathEntityList));
        // 查询组件详情
        CommonResult<List<ComponentEntity>> queryRes = componentApi.batchQueryByIds(new ArrayList<>(componentIds));
        if (Objects.isNull(queryRes) || !queryRes.getCode().equals("200")) {
            return CommonResult.error().setErrorCode("query.component.info.error")
                    .setMessage("组件信息查询失败");
        }
        List<ComponentEntity> componentEntityList = queryRes.getData();
        resMap.put("componentInfo", componentEntityList);
        resMap.put("routeRootPath", routerPathEntityList);
        resMap.put("menuInfo", parentInfo);
        // 添加缓存
        addMenuRegisterQueryRedisCache(resMap, requestRouteTo);
        return CommonResult.success(resMap);
    }

    /**
    * @Author GroundDemo
    * @Description 添加组件注册查询缓存
    * @Date 11:57 2025/3/22
    * @Param [resMap,requestRouteTo]
    * @return void
    **/
    private void addMenuRegisterQueryRedisCache(Map<String, Object> resMap, String requestRouteTo) {
        String serialize = GsonUtils.serialize(resMap);
        RedisUtils.hashSet(YWU_MENU_REGISTER_QUERY_KEY, requestRouteTo, serialize);
        RedisUtils.setExpire(YWU_MENU_REGISTER_QUERY_KEY, 2, TimeUnit.HOURS);
    }

    /**
    * @Author GroundDemo
    * @Description 删除组件注册查询缓存
    * @Date 12:16 2025/3/22
    * @Param [requestRouteTo]
    * @return void
    **/
    private void deleteMenuRegisterQueryRedisCache(String requestRouteTo) {
        if (RedisUtils.hasHashKey(YWU_MENU_REGISTER_QUERY_KEY, requestRouteTo)) {
            RedisUtils.deleteHashKey(YWU_MENU_REGISTER_QUERY_KEY, requestRouteTo);
        }
    }

    /**
    * @Author GroundDemo
    * @Description 添加菜单内容查询缓存
    * @Date 12:51 2025/3/22
    * @Param [resMenuDtos]
    * @return void
    **/
    private void addMenuRouterInfoRedisCache(List<MenuDto> resMenuDtos) {
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        String serialize = GsonUtils.serialize(resMenuDtos);
        Integer id = currentContext.getYwuContextUser().getId();
        String tenantId = currentContext.getYwuContextTenant().getTenantId();
        RedisUtils.hashSet(YWU_MENU_ROUTE_INFO_KEY, tenantId + '-' + id, serialize);
        RedisUtils.setExpire(YWU_MENU_ROUTE_INFO_KEY, 1, TimeUnit.HOURS);
    }

    /**
    * @Author GroundDemo
    * @Description 删除菜单内容查询缓存
    * @Date 12:52 2025/3/22
    * @Param []
    * @return void
    **/
    private void deleteMenuRouterInfoRedisCache() {
        if (RedisUtils.hasKey(YWU_MENU_ROUTE_INFO_KEY)) {
            RedisUtils.deleteByKey(YWU_MENU_ROUTE_INFO_KEY);
        }
    }

    /**
    * @Author GroundDemo
    * @Description 根据菜单ID查询授权角色信息
    * @Date 11:46 2025/3/22
    * @Param [menuId]
    * @return java.util.List<com.ywu.standard.menu.entity.MenuPermissionEntity>
    **/
    private List<MenuPermissionEntity> getMenuPermissionRole(String menuId) {
        // 先查询缓存是否存在
        String redisInfo = RedisUtils.getHashByKey(YWU_MENU_PERMISSION_REDIS_KEY, menuId);
        if (Objects.nonNull(redisInfo)) {
            log.debug("menu permission using redis cache");
            return GsonUtils.deserializeList(redisInfo, MenuPermissionEntity.class);
        }
        MenuPermissionDto dto = new MenuPermissionDto();
        dto.setMenuId(menuId);
        List<MenuPermissionEntity> permissionList = menuRepository.queryMenuPermission(dto);
        // 添加到缓存中
        RedisUtils.hashSet(YWU_MENU_PERMISSION_REDIS_KEY, menuId, GsonUtils.serialize(permissionList));
        return permissionList;
    }

    /**
    * @Author GroundDemo
    * @Description 向上卷积父菜单
    * @Date 11:08 2024/8/18
    * @Param [collect, dto]
    * @return com.ywu.standard.menu.dto.MenuDto
    **/
    private MenuDto getMenuParentInfo(Map<Integer, MenuEntity> collect, MenuDto dto, Set<Integer> routeRootIds,
                                      Set<Integer> componentIds) {
        // 记录一些变量后续使用
        routeRootIds.add(dto.getRouteRootId());
        if (dto.getMenuType().equals("DYNAMIC")) {
            componentIds.add(dto.getComponentId());
        }
        if (dto.getParentId() != 0) {
            MenuEntity parent = collect.get(dto.getParentId());
            MenuDto parentDto = new MenuDto();
            BeanUtils.copyProperties(parent, parentDto);
            parentDto.setChildren(Collections.singletonList(dto));
            return getMenuParentInfo(collect, parentDto, routeRootIds, componentIds);
        } else {
            return dto;
        }
    }

    /**
    * @Author GroundDemo
    * @Description 更新菜单是否隐藏
    * @Date 19:38 2024/9/21
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> updateMenuIsHidden(MenuDto menuDto) {
        menuRepository.updateMenuIsHidden(menuDto);
        return CommonResult.success(null);
    }

    /**
    * @Author GroundDemo
    * @Description 更新组件时删除缓存
    * @Date 12:30 2025/7/5
    * @Param [menuDto]
    * @return com.ywu.common.result.CommonResult<java.lang.Object>
    **/
    public CommonResult<Object> deleteRegisterCache(MenuDto menuDto) {
        List<MenuEntity> entityList = menuRepository.queryByComponentId(menuDto.getComponentId());
        for (MenuEntity entity : entityList) {
            String routeTo = entity.getRouteTo();
            RedisUtils.deleteHashKey(YWU_MENU_REGISTER_QUERY_KEY, routeTo);
        }
        return CommonResult.success(null);
    }
}
